﻿#include <QMessageBox>
#include <QApplication>
#include <QWheelEvent>
#include <QMenu>
#include <Configuration.h>
#include <Constants.h>
#include <Resources.h>
#include "MessageBrowser.h"

#define ZOOM_MAX 100
#define ZOOM_MIN 5

namespace Domy {

/**
 * @brief MessageBrowser
 * @note  消息浏览器
 */
MessageBrowser::MessageBrowser(QWidget *parent)
    : QPlainTextEdit(parent),
      m_zoom(1),
      m_highlighter(new MessageSearchHighlighter(this))
{
    this->setReadOnly(true);
    this->setContextMenuPolicy(Qt::CustomContextMenu);

    m_zoom = domy_config->getSettingsValue(SettingsGroup_Message, SettingsKey_MessageViewZoom).toInt();
    int zoom = m_zoom - DefaultSettings_MessageViewZoom;
    zoom = (m_zoom <= 100 && m_zoom >= 5) ? zoom : DefaultSettings_MessageViewZoom;
    this->zoomIn(zoom);

    connect(this, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(slotOnCustomContextMenuRequest(const QPoint &)));
}

MessageBrowser::~MessageBrowser()
{

}

void MessageBrowser::findText(const QString &text, bool is_case_sensitive, bool is_whole_word)
{
    QTextDocument::FindFlags flags = getFindFlags(false, is_case_sensitive, is_whole_word);

    QTextCursor cursor = this->document()->find(text, 0, flags);

    if (cursor.isNull()) {
        QMessageBox::information(this, tr("Not Found"), tr("Text \"%1\" not found !").arg(text),
                                 QMessageBox::Ok, QMessageBox::Ok);
        m_highlighter->clearSearchHighlight();
        m_highlighter->setDocument(this->document());
        return;
    }

    this->setFocus();

    this->setTextCursor(cursor);

    m_highlighter->setSearchHighlight(text, is_case_sensitive, is_whole_word);

    m_highlighter->setDocument(this->document());
}

bool MessageBrowser::findNext(const QString &text, bool is_case_sensitive, bool is_whole_word)
{
    this->setFocus();

    QTextDocument::FindFlags flags = getFindFlags(false, is_case_sensitive, is_whole_word);

    return this->find(text, flags);
}

bool MessageBrowser::findPrevious(const QString &text, bool is_case_sensitive, bool is_whole_word)
{
    this->setFocus();

    QTextDocument::FindFlags flags = getFindFlags(true, is_case_sensitive, is_whole_word);

    return this->find(text, flags);
}

void MessageBrowser::clearFindResult()
{
    m_highlighter->clearSearchHighlight();

    m_highlighter->setDocument(this->document());
}

QString MessageBrowser::getSelectedText() const
{
    return textCursor().selectedText();
}

void MessageBrowser::zoomViewIn()
{
    if (m_zoom < ZOOM_MAX) {
        this->zoomIn(1);
        ++m_zoom;

        triggerZoomChange();
    }
}

void MessageBrowser::zoomViewOut()
{
    if (m_zoom > ZOOM_MIN) {
        this->zoomOut(1);
        --m_zoom;

        triggerZoomChange();
    }
}

void MessageBrowser::zoomViewReset()
{
    this->zoomIn(DefaultSettings_MessageViewZoom - m_zoom);

    m_zoom = DefaultSettings_MessageViewZoom;

    triggerZoomChange();
}

void MessageBrowser::wheelEvent(QWheelEvent *e)
{
    if (qApp->keyboardModifiers() == Qt::ControlModifier) {

        bool is_zoom_change = false;

        if (e->delta() > 0 && m_zoom < ZOOM_MAX) {
            // 放大
            this->zoomIn(1);
            ++m_zoom;

            is_zoom_change = true;
        }
        else if (e->delta() < 0 && m_zoom > ZOOM_MIN) {
            // 缩小
            this->zoomOut(1);
            --m_zoom;

            is_zoom_change = true;
        }

        if (is_zoom_change) {
            triggerZoomChange();
        }
    }
    else {
        QPlainTextEdit::wheelEvent(e);
    }
}

void MessageBrowser::slotOnCustomContextMenuRequest(const QPoint &pos)
{
    QMenu menu;
    QAction *act_copy = menu.addAction(GET_ICON("copy"), tr("Copy"));
    menu.addSeparator();
    QAction *act_select = menu.addAction(GET_ICON("select_all"), tr("Select All"));

    act_copy->setEnabled(!this->textCursor().selectedText().isEmpty());
    act_select->setEnabled(!this->document()->isEmpty());

    QAction *act = menu.exec(QCursor::pos());
    if (!act) {
        return;
    }

    if (act == act_copy) {
        // copy
        this->copy();
    }
    else if (act == act_select) {
        // select all
        this->selectAll();
    }
    else {

    }
}

QTextDocument::FindFlags MessageBrowser::getFindFlags(bool is_backward, bool is_case_sensitive, bool is_whole_word)
{
    QTextDocument::FindFlags flags;
    if (is_backward) {
        flags |= QTextDocument::FindBackward;
    }

    if (is_case_sensitive) {
        flags |= QTextDocument::FindCaseSensitively;
    }

    if (is_whole_word) {
        flags |= QTextDocument::FindWholeWords;
    }

    return flags;
}

void MessageBrowser::triggerZoomChange()
{
    domy_config->setSettingsValue(SettingsGroup_Message, SettingsKey_MessageViewZoom, m_zoom);

    emit signalZoomChanged(m_zoom);
}

/**
 * @brief MessageSearchHighlighter
 * @note  消息搜索高亮
 */
MessageSearchHighlighter::MessageSearchHighlighter(QObject *parent)
    : QSyntaxHighlighter(parent)
{
    m_search_format.setBackground(QColor(248, 201, 171));
    m_search_format.setForeground(Qt::black);
    m_search_format.setFontWeight(QFont::Normal);
    m_search_format.setFontItalic(false);
    m_search_format.setFontUnderline(false);
}

MessageSearchHighlighter::~MessageSearchHighlighter()
{

}

void MessageSearchHighlighter::setSearchHighlight(const QString &text, bool is_case_sensitive, bool is_whole_word)
{
    QString exp = QString("%1%2%3")
            .arg(is_whole_word ? "\\b" : "")
            .arg(text)
            .arg(is_whole_word ? "\\b" : "");

    m_search_exp = QRegExp(exp, is_case_sensitive ? Qt::CaseSensitive : Qt::CaseInsensitive);
}

void MessageSearchHighlighter::clearSearchHighlight()
{
    m_search_exp = QRegExp();
}

void MessageSearchHighlighter::highlightBlock(const QString &text)
{
    if (m_search_exp.pattern().isEmpty()) {
        return;
    }
    QRegExp expression(m_search_exp);
    int index = text.indexOf(expression);
    while (index >= 0) {
        int length = expression.matchedLength();
        setFormat(index, length, m_search_format);
        index = text.indexOf(expression, index + length);
    }
    setCurrentBlockState(0);
}


} // namespace Domy
